const debug = require('debug')('qcloud-sdk[auth]')
const http = require('axios')
const uuidGenerator = require('uuid/v4')
const moment = require('moment')
const config = require('../config')
const sha1 = require('./sha1')
const aesDecrypt = require('./aesDecrypt')
const { ERRORS, LOGIN_STATE } = require('./constants')
const {WxUser} = require('../models')
/**
 * 授权模块
 * @param {express request} req
 * @return {Promise}
 * @example 基于 Express
 * authorization(this.req).then(userinfo => { // ...some code })
 */
function authorization (req) {
  const {
    'x-wx-code': code,
    'x-wx-encrypted-data': encryptedData,
    'x-wx-iv': iv
  } = req.headers

  // 检查 headers
  if ([code, encryptedData, iv].some(v => !v)) {
    debug(ERRORS.ERR_HEADER_MISSED)
    throw new Error(ERRORS.ERR_HEADER_MISSED)
  }

  debug('Auth: code: %s, encryptedData: %s, iv: %s', code, encryptedData, iv)

  // 获取 session key
  return getSessionKey(code)
    .then(pkg => {
      const { session_key } = pkg // eslint-disable-line
      // 生成 3rd_session
      const skey = sha1(session_key)

      // 解密数据
      let decryptedData
      try {
        decryptedData = aesDecrypt(session_key, iv, encryptedData)
        decryptedData = JSON.parse(decryptedData)
      } catch (e) {
        debug('Auth: %s: %o', ERRORS.ERR_IN_DECRYPT_DATA, e)
        throw new Error(`${ERRORS.ERR_IN_DECRYPT_DATA}\n${e}`)
      }
      // return {
      //   loginState: LOGIN_STATE.SUCCESS,
      //   userinfo: decryptedData,
      //   skey,
      //   session_key
      // }
      const user_info = JSON.stringify(decryptedData) // eslint-disable-line
      const open_id = decryptedData.openId // eslint-disable-line
      const create_time = moment().format('YYYY-MM-DD HH:mm:ss') // eslint-disable-line
      const last_visit_time = create_time // eslint-disable-line
      const uuid = uuidGenerator()
      return WxUser.insertOrUpdate({
        skey, uuid, create_time, last_visit_time, open_id, user_info, session_key
      }).then(result => {
        return {
          loginState: LOGIN_STATE.SUCCESS,
          userinfo: decryptedData,
          skey
        }
      })
    })
}

/**
 * 鉴权模块
 * @param {express request} req
 * @return {Promise}
 * @example 基于 Express
 * validation(this.req).then(loginState => { // ...some code })
 */
function validation (req) {
  const { 'x-wx-skey': skey } = req.headers
  if (!skey) throw new Error(ERRORS.ERR_SKEY_INVALID)

  return WxUser.findOne({
    where: {
      skey
    }
  }).then(result => {
    if (!result.dataValues) throw new Error(ERRORS.ERR_SKEY_INVALID)
    else result = result.dataValues
    // // 效验登录态是否过期
    const { last_visit_time: lastVisitTime, user_info: userInfo } = result
    const expires = config.wxLoginExpires && !isNaN(parseInt(config.wxLoginExpires)) ? parseInt(config.wxLoginExpires) * 1000 : 7200 * 1000
    if (moment(lastVisitTime, 'YYYY-MM-DD HH:mm:ss').valueOf() + expires < Date.now()) {
      return {
        loginState: LOGIN_STATE.FAILED,
        userinfo: {}
      }
    } else {
      return {
        loginState: LOGIN_STATE.SUCCESS,
        userinfo: JSON.parse(userInfo)
      }
    }
  })
}

/**
 * session key 交换
 * @param {string} appid
 * @param {string} appsecret
 * @param {string} code
 * @return {Promise}
 */
function getSessionKey (code) {
  const appid = config.appId
  const appsecret = config.appSecret

  return http({
    url: 'https://api.weixin.qq.com/sns/jscode2session',
    method: 'GET',
    params: {
      appid: appid,
      secret: appsecret,
      js_code: code,
      grant_type: 'authorization_code'
    }
  }).then(res => {
    res = res.data
    if (res.errcode || !res.openid || !res.session_key) {
      debug('%s: %O', ERRORS.ERR_GET_SESSION_KEY, res.errmsg)
      throw new Error(`${ERRORS.ERR_GET_SESSION_KEY}\n${JSON.stringify(res)}`)
    } else {
      debug('openid: %s, session_key: %s', res.openid, res.session_key)
      return res
    }
  })
}

module.exports = {
  authorization,
  validation
}
